//
// Created by bubbles on 2025/3/15.
//
#include "Menu.h"
extern int OLED_LINE;
MenuControler globalMenuControler;

/**
 * @brief 空函数测试用的
 */
void block_test_func(){};

/**
 * @brief 初始化 rangeBlock
 * @param rb 页面结构体指针
 * @param lower 总下界
 * @param upper 总上界
 * @param lowerValue 当前下界
 * @param upperValue 当前上界
 * @param initValue 选中值的初始值
 */
void rangeBlock_init(rangeBlock *rb, int lower, int upper, int lowerValue, int upperValue, int initValue) {
  rb->lower = lower;
  rb->upper = upper;
  rb->lowerValue = lowerValue;
  rb->upperValue = upperValue;
  rb->value = initValue;
}


/**
 * @brief 增加 value使得页面向下选择
 * @param rb 页面结构体指针
 */
void rangeBlock_increment(rangeBlock *rb) {
  // 先判断是否与 upperValue 相等
  if (rb->value == rb->upperValue) {
    // 只有当 upperValue 小于上界时，才移动
    if (rb->upperValue < rb->upper) {
      rb->upperValue++;
      rb->lowerValue++;
      rb->value++;
    }
  } else if (rb->value < rb->upperValue) {
    rb->value++;
  }
}

/**
 * @brief 减少 value使得页面向上选择
 * @param rb 页面结构体指针
 */
void rangeBlock_decrement(rangeBlock *rb) {
  // 先判断是否与 lowerValue 相等
  if (rb->value == rb->lowerValue) {
    // 只有当 lowerValue 大于下界时，才移动
    if (rb->lowerValue > rb->lower) {
      rb->upperValue--;
      rb->lowerValue--;
      rb->value--;
    }
  } else if (rb->value > rb->lowerValue) {
    rb->value--;
  }
}



/**
 * @brief 元夹初始化函数（接收可变参数列表）
 * @param desc 元夹指针
 * @param parent 父节点
 * @param ... 多个子节点元结构体
 * @return 生成的节点指针
 */
MenuNode *createContainerNode(const char *desc, MenuNode *parent, ...) {
  MenuNode *node = (MenuNode *)malloc(sizeof(MenuNode));
  if (!node) return NULL; // 分配失败处理

  node->description = strdup(desc);
  node->action = NULL;               // 元夹时功能函数为空
  node->isFunction = 0;              // 标记为元夹
  node->parent = parent;             // 设置父单元指针

  // 统计子单元数量
  va_list args;
  va_start(args, parent);
  int subItemCount = 0;
  while (va_arg(args, MenuNode *) != NULL) {
    subItemCount++;
  }
  va_end(args);

  // 分配子单元指针数组并重新遍历参数列表
  node->subItems = (MenuNode **)malloc((subItemCount + 1) * sizeof(MenuNode *));
  va_start(args, parent);
  for (int i = 0; i < subItemCount; i++) {
    node->subItems[i] = va_arg(args, MenuNode *);
    node->subItems[i]->parent = node; // 设置每个子单元的父指针
  }
  node->subItems[subItemCount] = NULL; // 数组最后一项设为 NULL 以标识结束
  va_end(args);

  return node;
}

/**
 * @brief 功能元初始化函数（接收可变参数列表）
 * @param desc 元夹指针
 * @param func 功能函数
 * @param parent 父节点
 * @param ... 可选的指令（字符串），只会读取第一个指令，其余舍弃
 * @return 生成的节点指针
 */
MenuNode *createFunctionNode(const char *desc, void (*func)(void), MenuNode *parent, ...) {
  MenuNode *node = (MenuNode *)malloc(sizeof(MenuNode));
  if (!node) return NULL; // 分配失败处理

  node->oder = NULL;
  va_list args;
  va_start(args, parent);
  char* oder = va_arg(args, char*);
  if(oder != NULL){
    node->oder = oder;
  }
  va_end(args);
  node->description = strdup(desc);
  node->subItems = NULL;
  node->action = func;
  node->isFunction = 1;
  node->parent = parent;
  return node;
}

/**
 * @brief 递归释放菜单节点及其所有子节点的内存
 * @param node 节点指针
 */
void freeMenuNode(MenuNode *node) {
  if (node) {
    free(node->description);

    // 递归释放子节点
    if (!node->isFunction && node->subItems) {
      for (int i = 0; node->subItems[i] != NULL; i++) {
        freeMenuNode(node->subItems[i]);
      }
      free(node->subItems);
    }
    free(node);
  }
}


/**
 * @brief 统计一个节点所有的子节点个数
 * @param node 节点指针
 * @return 节点个数
 */
int countSubItems(MenuNode *node) {
  if (node == NULL || node->subItems == NULL) {
    return 0; // 如果节点为空或没有子单元，则返回 0
  }
  int count = 0;
  for (int i = 0; node->subItems[i] != NULL; i++) {
    count++; // 统计每个子单元
  }
  return count; // 返回统计结果
}

/**@brief 初始化 MenuControler
 * @param controller 操作体指针
 * @param rootMenu 操作体指向的根节点指针
 */
void initMenuControler(MenuControler *controller, MenuNode *rootMenu) {
  if (controller == NULL) return; // 检查 controller 是否为空
  controller->currentMenu = rootMenu;
  int count = countSubItems(rootMenu);
  controller->totalItems = 0;
  if(count <= OLED_LINE){
    rangeBlock_init(&(controller->selectedIdx), 0, count-1, 0, count-1, 0);
  }
  else rangeBlock_init(&(controller->selectedIdx), 0, count-1, 0, OLED_LINE - 1, 0);
  if (rootMenu) {
    if (!rootMenu->isFunction && rootMenu->subItems) {
      // 计算当前菜单的子单元数量
      while (rootMenu->subItems[controller->totalItems] != NULL) {
        controller->totalItems++;
      }
      // 更新 rangeNum 的 upper 边界
      controller->selectedIdx.upper = controller->totalItems > 0 ? controller->totalItems - 1 : 0;
    } else {
      // 若没有子单元，将 upper 设置为 0
      controller->selectedIdx.upper = 0;
    }
  }
}

/**
 * @brief 减少选择器的数值，即形式页面上移
 * @param controller 操作体指针
 */
void decrementSelection(MenuControler *controller) {
  if (controller == NULL) return; // 检查 controller 是否为空
  rangeBlock_decrement(&(controller->selectedIdx));
}

/**
 * @brief 增加选择器的数值，即形式页面下移
 * @param controller 操作体指针
 */
void incrementSelection(MenuControler *controller) {
  if (controller == NULL) return; // 检查 controller 是否为空
  rangeBlock_increment(&(controller->selectedIdx));
}

/**
 * @brief 退出选中节点操作器进入父节点，即形式页面回退上一级
 * @param controller 操作体指针
 */
void exitMenu(MenuControler *controller) {
  if (controller == NULL || !controller->currentMenu) return; // 检查 controller 和 currentMenu 是否为空
  MenuNode * selectedNode = controller->currentMenu->parent;
  if(selectedNode == NULL) return;
  initMenuControler(controller, selectedNode);
}

/**
 * @brief 使用选中节点操作器当前指向的节点，即进入子元夹或使用子函数
 * @param controller 操作体指针
 */
void useSelected(MenuControler * controller){
  if (controller == NULL || !controller->currentMenu) return; // 检查 controller 和 currentMenu 是否为空
  int num = controller->selectedIdx.value;
  MenuNode * selectedNode = controller->currentMenu->subItems[num];
  if (controller->currentMenu->subItems) {
    if (selectedNode) {
      if (selectedNode->isFunction && selectedNode->action) {
        // 功能元则执行功能
        if(selectedNode->oder == NULL){
          selectedNode->action();
        }
        else{
          ((void (*)(char*)) (selectedNode->action)) (selectedNode->oder);
        }
      } else {
        // 元夹则进入该元夹
        initMenuControler(controller, selectedNode);
      }
    }
  }
}


/**
 * @brief 菜单节点控制器的打印函数(输出到缓冲区)。菜单节点控制器能表示当前节点的状态：该菜单、当前选中的子菜单、子菜单的个数。该函数能打印出这种状态。
 * @param Controler 菜单节点控制器
 */
void menuOLED_MenuControl_Print(MenuControler * Controler){
  MenuNode *ThisNode = Controler->currentMenu;
  int count = countSubItems(ThisNode);
  int i=1;
  if(count < OLED_LINE){
    for(i=1; i<=count; i++){
      int j = Controler->selectedIdx.lowerValue;
      int value = Controler->selectedIdx.value;
      MenuNode *subNode = ThisNode->subItems[j+i-1];
      if(i+j == (value+1)){
        menuOLED_LineX_R(subNode, i);
      }
      else menuOLED_LineX_N(subNode, i);
    }
    return;
  }
  for(i=1; i<=OLED_LINE; i++){
    int j = Controler->selectedIdx.lowerValue;
    int value = Controler->selectedIdx.value;
    MenuNode *subNode = ThisNode->subItems[j+i-1];
    if(i+j == (value+1)){
      menuOLED_LineX_R(subNode, i);
    }
    else menuOLED_LineX_N(subNode, i);
  }
}

__attribute__((weak)) void MenuOLED_PrintString_N(uint8_t x, uint8_t y, char *str){

}
__attribute__((weak)) void MenuOLED_PrintString_R(uint8_t x, uint8_t y, char *str){

}
/**
 * @brief 字符串输出到缓冲区，指定打横坐标为0，纵坐标指定行，但能打印"节点"的描述，注意字符串效果为正常，
 * @param MenuNode 菜单节点
 * @param line 行数
 */
__attribute__((weak)) void menuOLED_LineX_N(MenuNode * MenuNode, int line){
  MenuOLED_PrintString_N(0, (line-1)*16, MenuNode->description);
}

/**
 * @brief 字符串输出到缓冲区，简单的包装，指定打横坐标为0，纵坐标指定行，但能打印"节点"的描述，注意字符串效果为反转，
 * @param MenuNode 菜单节点
 * @param line 行数
 */
__attribute__((weak)) void menuOLED_LineX_R(MenuNode * MenuNode, int line){
  MenuOLED_PrintString_R(0, (line-1)*16, MenuNode->description);
}

